home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / alpha.arc / SMTPSERV.C < prev    next >
C/C++ Source or Header  |  1988-07-24  |  18KB  |  794 lines

  1. /* SMTP Server state machine - see RFC 821
  2.  *  enhanced 4/88 Dave Trulli nn2z
  3.  */
  4. #include <stdio.h>
  5. #include <time.h>
  6. #ifdef UNIX
  7. #include <sys/types.h>
  8. #endif
  9. #include <ctype.h>
  10. #include "global.h"
  11. #include "mbuf.h"
  12. #include "netuser.h"
  13. #include "timer.h"
  14. #include "tcp.h"
  15. #include "smtp.h"
  16.  
  17. char *getname();
  18. void mail_delete();
  19. static int rqueuejob();
  20. int queuejob();
  21. int validate_address();
  22. long get_msgid();
  23. struct list *addlist();
  24. struct list * expandalias();
  25.  
  26. /* Command table */
  27. static char *commands[] = {
  28.     "helo",
  29. #define    HELO_CMD    0
  30.     "noop",
  31. #define    NOOP_CMD    1
  32.     "mail from:",
  33. #define    MAIL_CMD    2
  34.     "quit",
  35. #define    QUIT_CMD    3
  36.     "rcpt to:",
  37. #define    RCPT_CMD    4
  38.     "help",
  39. #define    HELP_CMD    5
  40.     "data",
  41. #define    DATA_CMD    6
  42.     "rset",
  43. #define    RSET_CMD    7
  44.     NULLCHAR
  45. };
  46.  
  47. /* Reply messages */
  48. static char help[] = "214-Commands:\r\n214-HELO NOOP MAIL QUIT RCPT HELP DATA RSET\r\n214 End\r\n";
  49. static char banner[] = "220 %s SMTP ready\r\n";
  50. static char closing[] = "221 Closing\r\n";
  51. static char ok[] = "250 Ok\r\n";
  52. static char reset[] = "250 Reset state\r\n";
  53. static char sent[] = "250 Sent\r\n";
  54. static char ourname[] = "250 %s, Share and Enjoy!\r\n";
  55. static char enter[] = "354 Enter mail, end with .\r\n";
  56. static char ioerr[] = "452 Temp file write error\r\n";
  57. static char mboxerr[] = "452 Mailbox write error\r\n";
  58. static char badcmd[] = "500 Command unrecognized\r\n";
  59. static char syntax[] = "501 Syntax error\r\n";
  60. static char needrcpt[] = "503 Need RCPT (recipient)\r\n";
  61. static char unknown[] = "550 <%s> address unknown\r\n";
  62.  
  63. static struct tcb *smtp_tcb;
  64. /* Start up SMTP receiver service */
  65. smtp1(argc,argv)
  66. int argc;
  67. char *argv[];
  68. {
  69.     struct socket lsocket;
  70.     void r_mail(),s_mail();
  71.  
  72.     lsocket.address = ip_addr;
  73.     if(argc < 2)
  74.         lsocket.port = SMTP_PORT;
  75.     else
  76.         lsocket.port = atoi(argv[1]);
  77.  
  78.     smtp_tcb = open_tcp(&lsocket,NULLSOCK,
  79.         TCP_SERVER,0,r_mail,NULLVFP,s_mail,0,(char *)NULL);
  80. }
  81.  
  82. /* Shutdown SMTP service (existing connections are allowed to finish) */
  83. smtp0()
  84. {
  85.     if(smtp_tcb != NULLTCB)
  86.         close_tcp(smtp_tcb);
  87. }
  88.  
  89. /* SMTP connection state change upcall handler */
  90. static void
  91. s_mail(tcb,old,new)
  92. struct tcb *tcb;
  93. char old,new;
  94. {
  95.     struct mail *mp,*mail_create();
  96.  
  97.     switch(new){
  98. #ifdef    QUICKSTART
  99.     case SYN_RECEIVED:
  100. #else
  101.     case ESTABLISHED:
  102. #endif
  103.         if((mp = mail_create(tcb)) == NULLMAIL){
  104.             close_tcp(tcb);
  105.             break;
  106.         }
  107.         (void) tprintf(mp->tcb,banner,hostname);
  108.         log(tcb,"open SMTP");
  109.         break;        
  110.     case CLOSE_WAIT:
  111.         close_tcp(tcb);
  112.         break;
  113.     case CLOSED:
  114.         log(tcb,"close SMTP");
  115.         mp = (struct mail *)tcb->user;
  116.         mail_delete(mp);                
  117.         del_tcp(tcb);
  118.         /* Check if server is being shut down */
  119.         if(tcb == smtp_tcb)
  120.             smtp_tcb = NULLTCB;
  121.         break;
  122.     }
  123. }
  124.  
  125. /* SMTP receiver upcall handler */
  126. static void
  127. r_mail(tcb,cnt)
  128. struct tcb *tcb;
  129. int16 cnt;
  130. {
  131.     register struct mail *mp;
  132.     char c;
  133.     struct mbuf *bp;
  134.     char *inet_ntoa();
  135.     void docommand(),doline();
  136.  
  137.     if((mp = (struct mail *)tcb->user) == NULLMAIL){
  138.         /* Unknown session */
  139.         close_tcp(tcb);
  140.         return;
  141.     }
  142.     recv_tcp(tcb,&bp,cnt);
  143.     /* Assemble an input line in the session buffer.
  144.      * Return if incomplete
  145.      */
  146.     while(pullup(&bp,&c,1) == 1){
  147.         switch(c){
  148.         case '\r':    /* Strip cr's */
  149. #ifdef MSDOS
  150.         case '\032':    /* Strip ctrl/Z's */
  151. #endif
  152.             continue;
  153.         case '\n':    /* Complete line; process it */
  154.             mp->buf[mp->cnt] = '\0';
  155.             doline(mp);
  156.             break;
  157.         default:    /* Assemble line */
  158.             if(mp->cnt != LINELEN-1)
  159.                 mp->buf[mp->cnt++] = c;
  160.             break;
  161.         }
  162.     }
  163. }
  164. /* Process a line read on an SMTP connection (any state) */
  165. static void
  166. doline(mp)
  167. register struct mail *mp;
  168. {
  169.     void docommand(),deliver();
  170.  
  171.     switch(mp->state){
  172.     case COMMAND_STATE:
  173.         docommand(mp);
  174.         break;
  175.     case DATA_STATE:
  176.         tcp_output(mp->tcb);    /* Send ACK; disk I/O is slow */
  177.         if(mp->buf[0] == '.' && mp->buf[1] == '\0'){
  178.             mp->state = COMMAND_STATE;
  179.         /* Also sends appropriate response */
  180.             deliver(mp);
  181.             fclose(mp->data);
  182.             mp->data = NULLFILE;
  183.             del_list(mp->to);
  184.             mp->to = NULLLIST;
  185.             break;
  186.         }
  187.         /* for UNIX mail compatiblity */
  188.         if (strncmp(mp->buf,"From ",5) == 0)
  189.             (void) putc('>',mp->data);
  190.         /* Append to data file */
  191.         if(fprintf(mp->data,"%s\n",mp->buf) < 0){
  192.             mp->state = COMMAND_STATE;
  193.             (void) tprintf(mp->tcb,ioerr);
  194.         }
  195.         break;
  196.     }
  197.     mp->cnt = 0;
  198. }
  199. /* Create control block, initialize */
  200. static struct mail *
  201. mail_create(tcb)
  202. register struct tcb *tcb;
  203. {
  204.     register struct mail *mp;
  205.  
  206.     if((mp = (struct mail *)calloc(1,sizeof (struct mail))) == NULLMAIL)
  207.         return NULLMAIL;
  208.     mp->tcb = tcb;        /* Downward pointer */
  209.     tcb->user = (char *)mp;    /* Upward pointer */
  210.     return mp;
  211. }
  212.  
  213. /* Free resources, delete control block */
  214. static void
  215. mail_delete(mp)
  216. register struct mail *mp;
  217. {
  218.  
  219.     if (mp == NULLMAIL)
  220.         return;
  221.     if(mp->system != NULLCHAR)
  222.         free(mp->system);
  223.     if(mp->from != NULLCHAR)
  224.         free(mp->from);
  225.     if(mp->data != NULLFILE)
  226.         fclose(mp->data);
  227.     del_list(mp->to);
  228.     free((char *)mp);
  229. }
  230.  
  231. /* Parse and execute mail commands */
  232. static void
  233. docommand(mp)
  234. register struct mail *mp;
  235. {
  236.     register char **cmdp,*arg,*cp,*cmd;
  237.     struct list *ap;
  238.     FILE *tmpfile();
  239.     long t;
  240.     char address_type;
  241.  
  242.     cmd = mp->buf;
  243.     if(mp->cnt < 4){
  244.         /* Can't be a legal SMTP command */
  245.         (void) tprintf(mp->tcb,badcmd);
  246.         return;
  247.     }    
  248.     cmd = mp->buf;
  249.  
  250.     /* Translate entire buffer to lower case */
  251.     for(cp = cmd;*cp != '\0';cp++)
  252.         *cp = tolower(*cp);
  253.  
  254.     /* Find command in table; if not present, return syntax error */
  255.     for(cmdp = commands;*cmdp != NULLCHAR;cmdp++)
  256.         if(strncmp(*cmdp,cmd,strlen(*cmdp)) == 0)
  257.             break;
  258.     if(*cmdp == NULLCHAR){
  259.         (void) tprintf(mp->tcb,badcmd);
  260.         return;
  261.     }
  262.     arg = &cmd[strlen(*cmdp)];
  263.     /* Skip spaces after command */
  264.     while(*arg == ' ')
  265.         arg++;
  266.     /* Execute specific command */
  267.     switch(cmdp-commands){
  268.     case HELO_CMD:
  269.         if(mp->system != NULLCHAR)
  270.             free(mp->system);
  271.         if((mp->system = malloc((unsigned)strlen(arg)+1)) == NULLCHAR){
  272.             /* If the system is out of memory, just close */
  273.             close_tcp(mp->tcb);
  274.             break;            
  275.         } else {
  276.             strcpy(mp->system,arg);
  277.             (void) tprintf(mp->tcb,ourname,hostname);
  278.         }
  279.         break;
  280.     case NOOP_CMD:
  281.         (void) tprintf(mp->tcb,ok);
  282.         break;
  283.     case MAIL_CMD:
  284.         if(mp->from != NULLCHAR)
  285.             free(mp->from);
  286.         if((mp->from = malloc((unsigned)strlen(arg)+1)) == NULLCHAR){
  287.             /* If the system is out of memory, just close */
  288.             close_tcp(mp->tcb);
  289.             break;            
  290.         } else {
  291.             if((cp = getname(arg)) == NULLCHAR){
  292.                 (void) tprintf(mp->tcb,syntax);
  293.                 break;
  294.             }
  295.             strcpy(mp->from,cp);
  296.             (void) tprintf(mp->tcb,ok);
  297.         }
  298.         break;
  299.     case QUIT_CMD:
  300.         (void) tprintf(mp->tcb,closing);
  301.         close_tcp(mp->tcb);
  302.         break;
  303.     case RCPT_CMD:    /* Specify recipient */
  304.         if((cp = getname(arg)) == NULLCHAR){
  305.             (void) tprintf(mp->tcb,syntax);
  306.             break;
  307.         }
  308.  
  309.         /* check if address is ok */
  310.         if ((address_type = validate_address(cp)) == BADADDR) {
  311.             (void) tprintf(mp->tcb,unknown,cp);
  312.             break;
  313.         }
  314.         /* if a local address check for an alias */
  315.         if (address_type == LOCAL)
  316.             expandalias(&mp->to, cp);
  317.         else
  318.             /* a remote address is added to the list */
  319.             addlist(&mp->to, cp, address_type);
  320.  
  321.         (void) tprintf(mp->tcb,ok);
  322.         break;
  323.     case HELP_CMD:
  324.         (void) tprintf(mp->tcb,help);
  325.         break;
  326.     case DATA_CMD:
  327.         if(mp->to == NULLLIST){
  328.             (void) tprintf(mp->tcb,needrcpt);
  329.             break;
  330.         }
  331.         tcp_output(mp->tcb);    /* Send ACK; disk I/O is slow */
  332.         if((mp->data = tmpfile()) == NULLFILE){
  333.             (void) tprintf(mp->tcb,ioerr);
  334.             break;
  335.         }
  336.         /* Add timestamp; ptime adds newline */
  337.         time(&t);
  338.         fprintf(mp->data,"Received: ");
  339.         if(mp->system != NULLCHAR)
  340.             fprintf(mp->data,"from %s ",mp->system);
  341.         fprintf(mp->data,"by %s with SMTP\n\tid AA%ld ; %s",
  342.                 hostname, get_msgid(), ptime(&t));
  343.         if(ferror(mp->data)){
  344.             (void) tprintf(mp->tcb,ioerr);
  345.         } else {
  346.             mp->state = DATA_STATE;
  347.             (void) tprintf(mp->tcb,enter);
  348.         }
  349.         break;
  350.     case RSET_CMD:
  351.         del_list(mp->to);
  352.         mp->to = NULLLIST;
  353.         mp->state = COMMAND_STATE;
  354.         (void) tprintf(mp->tcb,reset);
  355.         break;
  356.     }
  357. }
  358. /* Given a string of the form <user@host>, extract the part inside the
  359.  * brackets and return a pointer to it.
  360.  */
  361. static
  362. char *
  363. getname(cp)
  364. register char *cp;
  365. {
  366.     register char *cp1;
  367.  
  368.     if((cp = index(cp,'<')) == NULLCHAR)
  369.         return NULLCHAR;
  370.     cp++;    /* cp -> first char of name */
  371.     if((cp1 = index(cp,'>')) == NULLCHAR)
  372.         return NULLCHAR;
  373.     *cp1 = '\0';
  374.     return cp;
  375. }
  376.  
  377. /* Deliver mail to the appropriate mail boxes and delete temp file */
  378. static
  379. void
  380. deliver(mp)
  381. register struct mail *mp;
  382. {
  383.     int ret;
  384.  
  385.     /* send to the rqueue */
  386.     if ((smtpmode & QUEUE) != 0) {
  387.         ret = router_queue(mp->tcb,mp->data,mp->from,mp->to);
  388.         if (ret != 0)
  389.             (void) tprintf(mp->tcb,ioerr);
  390.     } else {
  391.         ret = mailit(mp->tcb,mp->data,mp->from,mp->to);
  392.         if (ret != 0)
  393.             (void) tprintf(mp->tcb,mboxerr);
  394.     }
  395.     if (ret == 0)
  396.         (void) tprintf(mp->tcb,sent);
  397.         
  398. }
  399.  
  400. /* used to save local mail or reroute remote mail */
  401. mailit(tcb,data,from,to)
  402. struct tcb *tcb;
  403. FILE *data;
  404. char *from;
  405. struct list *to;
  406. {
  407.     register struct list *ap;
  408.     register FILE *fp;
  409.     int c;
  410.     char    mailbox[50];
  411.     char    *cp;
  412.     char    *desthost;
  413.     int    fail = 0;
  414.     time_t    t;
  415.     for(ap = to;ap != NULLLIST;ap = ap->next) {
  416.  
  417.         fseek(data,0L,0);    /* rewind */
  418.  
  419.         /* non local mail queue it */
  420.         if (ap->type == DOMAIN) {
  421.             if ((desthost = index(ap->val,'@')) != NULLCHAR);
  422.                 desthost++;
  423.             fail = queuejob(tcb,data,desthost,ap->val,from);
  424.         } else {
  425.             /* strip off host name */
  426.             if ((cp = index(ap->val,'@')) != NULLCHAR)
  427.                 *cp = '\0';
  428.  
  429.             /* truncate long user names */
  430.             if (strlen(ap->val) > MBOXLEN)
  431.                 ap->val[MBOXLEN] = '\0';
  432.  
  433.             /* if mail file is busy save it in our smtp queue
  434.              * and let the smtp daemon try later.
  435.              */
  436.             if (mlock(mailspool,ap->val))
  437.                 fail = queuejob(tcb,data,hostname,ap->val,from);
  438.             else {
  439.                 sprintf(mailbox,"%s/%s.txt",mailspool,ap->val);
  440.                 if((fp = fopen(mailbox,"a+")) != NULLFILE) {
  441.                     time(&t);
  442.                     fprintf(fp,
  443.                     "From %s %s",from,ctime(&t));
  444.                     while((c = getc(data)) != EOF)
  445.                         if(putc(c,fp) == EOF)
  446.                             break;
  447.                     if(ferror(fp))
  448.                         fail = 1;
  449.                     else
  450.                         fprintf(fp,"\n");
  451.                     /* Leave a blank line between msgs */
  452.                     fclose(fp);
  453.                     printf("New mail arrived for %s\n",ap->val);
  454.                     fflush(stdout);
  455.                 } else 
  456.                     fail = 1;
  457.                 (void) rmlock(mailspool,ap->val);
  458.                 if (fail)
  459.                     break;
  460.                 log(tcb,
  461.                 "SMTP recv: To: %s From: %s",ap->val,from);
  462.             }
  463.         }
  464.     }
  465. }
  466.  
  467. /* Return Date/Time in Arpanet format in passed string */
  468. char *
  469. ptime(t)
  470. long *t;
  471. {
  472.     /* Print out the time and date field as
  473.      *        "DAY day MONTH year hh:mm:ss ZONE"
  474.      */
  475.     register struct tm *ltm;
  476.     static char tz[4];
  477.     static char str[40];
  478.     extern char *getenv();
  479.     extern struct tm *localtime();
  480.     char *p;
  481.     static char *days[7] = {
  482.     "Sun","Mon","Tue","Wed","Thu","Fri","Sat" };
  483.  
  484.     static char *months[12] = {
  485.         "Jan","Feb","Mar","Apr","May","Jun",
  486.         "Jul","Aug","Sep","Oct","Nov","Dec" };
  487.  
  488.     /* Read the system time */
  489.     ltm = localtime(t);
  490.  
  491.     if (*tz == '\0')
  492.         if ((p = getenv("TZ")) == NULL)
  493.             strcpy(tz,"GMT");
  494.         else
  495.             strncpy(tz,p,3);
  496.  
  497.     /* rfc 822 format */
  498.     sprintf(str,"%s, %.2d %s %02d %02d:%02d:%02d %.3s\n",
  499.         days[ltm->tm_wday],
  500.         ltm->tm_mday,
  501.         months[ltm->tm_mon],
  502.         ltm->tm_year,
  503.         ltm->tm_hour,
  504.         ltm->tm_min,
  505.         ltm->tm_sec,
  506.         tz);
  507.     return(str);
  508. }
  509.  
  510. long 
  511. get_msgid()
  512. {
  513.     char sfilename[LINELEN];
  514.     char s[20];
  515.     register long sequence = 0;
  516.     FILE *sfile;
  517.     long atol();
  518.  
  519.     sprintf(sfilename,"%s/sequence.seq",mailqdir);
  520.     sfile = fopen(sfilename,"r");
  521.  
  522.     /* if sequence file exists, get the value, otherwise set it */
  523.     if (sfile != NULL) {
  524.         (void) fgets(s,sizeof(s),sfile);
  525.         sequence = atol(s);
  526.     /* Keep it in range of and 8 digit number to use for dos name prefix. */
  527.         if (sequence < 0L || sequence > 99999999L )
  528.             sequence = 0;
  529.         fclose(sfile);
  530.     }
  531.  
  532.     /* increment sequence number, and write to sequence file */
  533.     sfile = fopen(sfilename,"w");
  534.     fprintf(sfile,"%ld",++sequence);
  535.     fclose(sfile);
  536.     return sequence;
  537. }
  538.  
  539. #ifdef    MSDOS
  540. /* Illegal characters in a DOS filename */
  541. static char baddoschars[] = "\"[]:|<>+=;,";
  542. #endif
  543.  
  544. /* test if mail address is valid */
  545. static int
  546. validate_address(s)
  547. char *s;
  548. {
  549.     FILE *fp;
  550.     char *cp;
  551.     int32 addr;
  552.     char    address_type;
  553.     int32 mailroute();
  554.  
  555.  
  556.  
  557.     /* if address has @ in it the check dest address */
  558.     if ((cp = index(s,'@')) != NULLCHAR) {
  559.         cp++;
  560.         /* 1st check if its our hostname
  561.         * if not then check the hosts file and see
  562.         * if we can resolve ther address to a know site
  563.         * or one of our aliases
  564.         */
  565.         if (strcmp(cp,hostname) != 0) {
  566.             if ((addr = mailroute(cp)) == 0
  567.                 && (smtpmode & QUEUE) == 0)
  568.                 return BADADDR;
  569.             if (addr != ip_addr)
  570.                 return DOMAIN;
  571.         }
  572.         
  573.         /* on a local address remove the host name part */
  574.         *--cp = '\0';
  575.     }
  576.  
  577.     /* if using an external router leave address alone */
  578.     if ((smtpmode & QUEUE) != 0)
  579.         return LOCAL;
  580.  
  581.  
  582.     /* check for the user%host hack */
  583.     if ((cp = index(s,'%')) != NULLCHAR) {
  584.         *cp = '@';
  585.         cp++;
  586.         /* reroute based on host name following the % seperator */
  587.         if (mailroute(cp) == 0)
  588.             return BADADDR;
  589.         else
  590.             return DOMAIN;
  591.     }
  592.     address_type = LOCAL;
  593.  
  594. #ifdef MSDOS    /* dos file name checks */
  595.     /* Check for characters illegal in MS-DOS file names */
  596.     for(cp = baddoschars;*cp != '\0';cp++){
  597.         if(index(s,*cp) != NULLCHAR)
  598.             return BADADDR;    
  599.     }
  600. #endif
  601.     return LOCAL;
  602. }
  603.  
  604. /* place a mail job in the outbound queue */
  605. int
  606. queuejob(tcb,dfile,host,to,from)
  607. struct tcb *tcb;
  608. FILE *dfile;
  609. char *host,*to,*from;
  610. {
  611.     FILE *fp;
  612.     char tmpstring[50];
  613.     char prefix[9];
  614.     register int c;
  615.  
  616.     sprintf(prefix,"%ld",get_msgid());
  617.     log(tcb,"SMTP queue job %s To: %s From: %s",prefix,to,from);
  618.     mlock(mailqdir,prefix);
  619.     sprintf(tmpstring,"%s/%s.txt",mailqdir,prefix);
  620.     if((fp = fopen(tmpstring,"w")) == NULLFILE) {
  621.         (void) rmlock(mailqdir,prefix);
  622.         return 1;
  623.     }
  624.     while((c = getc(dfile)) != EOF)
  625.         if(putc(c,fp) == EOF)
  626.             break;
  627.     if(ferror(fp)){
  628.         fclose(fp);
  629.         (void) rmlock(mailqdir,prefix);
  630.         return 1;
  631.     }
  632.     fclose(fp);
  633.     sprintf(tmpstring,"%s/%s.wrk",mailqdir,prefix);
  634.     if((fp = fopen(tmpstring,"w")) == NULLFILE) {
  635.         (void) rmlock(mailqdir,prefix);
  636.         return 1;
  637.     }
  638.     fprintf(fp,"%s\n%s\n%s\n",host,from,to);
  639.     fclose(fp);
  640.     (void) rmlock(mailqdir,prefix);
  641.     return 0;
  642. }
  643.  
  644. /* Deliver mail to the appropriate mail boxes */
  645. int
  646. router_queue(tcb,data,from,to)
  647. struct tcb *tcb;
  648. FILE *data;
  649. char *from;
  650. struct list *to;
  651. {
  652.     int c;
  653.     register struct list *ap;
  654.     FILE *fp;
  655.     char tmpstring[50];
  656.     char prefix[9];
  657.  
  658.     sprintf(prefix,"%ld",get_msgid());
  659.     mlock(routeqdir,prefix);
  660.     sprintf(tmpstring,"%s/%s.txt",routeqdir,prefix);
  661.     if((fp = fopen(tmpstring,"w")) == NULLFILE) {
  662.         (void) rmlock(routeqdir,prefix);
  663.         return 1;
  664.     }
  665.     fseek(data,0L,0);    /* rewind */
  666.     while((c = getc(data)) != EOF)
  667.         if(putc(c,fp) == EOF)
  668.             break;
  669.     if(ferror(fp)){
  670.         fclose(fp);
  671.         (void) rmlock(routeqdir,prefix);
  672.         return 1;
  673.     }
  674.     fclose(fp);
  675.     sprintf(tmpstring,"%s/%s.wrk",routeqdir,prefix);
  676.     if((fp = fopen(tmpstring,"w")) == NULLFILE) {
  677.         (void) rmlock(routeqdir,prefix);
  678.         return 1;
  679.     }
  680.     fprintf(fp,"From: %s\n",from);
  681.     for(ap = to;ap != NULLLIST;ap = ap->next) {
  682.         fprintf(fp,"To: %s\n",ap->val);
  683.     }
  684.     fclose(fp);
  685.     (void) rmlock(routeqdir,prefix);
  686.     log(tcb,"SMTP rqueue job %s From: %s",prefix,from);
  687.     return 0;
  688. }
  689.  
  690. /* add an element to the front of the list pointed to by head 
  691. ** return NULLLIST if out of memory.
  692. */
  693. struct list *
  694. addlist(head,val,type)
  695. struct list **head;
  696. char *val;
  697. int type;
  698. {
  699.     register struct list *tp;
  700.  
  701.     tp = (struct list *)calloc(1,sizeof(struct list));
  702.     if (tp == NULLLIST)
  703.         return NULLLIST;
  704.  
  705.     tp->next = NULLLIST;
  706.  
  707.     /* allocate storage for the char string */
  708.     if ((tp->val = malloc((unsigned)strlen(val)+1)) == NULLCHAR) {
  709.         (void) free((char *)tp);
  710.         return NULLLIST;
  711.     }
  712.     strcpy(tp->val,val);
  713.     tp->type = type;
  714.  
  715.     /* add entry to front of existing list */
  716.     if (*head == NULLLIST)
  717.         *head = tp;
  718.     else {
  719.         tp->next = *head;
  720.         *head = tp;
  721.     }
  722.     return tp;
  723.  
  724. }
  725.  
  726. #define SKIPWORD(X) while(*X && *X!=' ' && *X!='\t' && *X!='\n' && *X!= ',') X++;
  727. #define SKIPSPACE(X) while(*X ==' ' || *X =='\t' || *X =='\n' || *X == ',') X++;
  728.  
  729. /* check for and alias and expand alias into a address list */
  730. struct list *
  731. expandalias(head, user)
  732. struct list **head;
  733. char *user;
  734. {
  735.     FILE *fp;
  736.     register char *s,*p,*h;
  737.     int inalias;
  738.     struct list *tp;
  739.     char buf[LINELEN];
  740.     
  741.     
  742.         /* no alias file found */
  743.     if ((fp = fopen(alias, "r")) == NULLFILE)
  744.         return addlist(head, user, LOCAL);
  745.  
  746.     inalias = 0;
  747.     while (fgets(buf,LINELEN,fp) != NULLCHAR) {
  748.         p = buf;
  749.         if ( *p == '#' || *p == '\0')
  750.             continue;
  751.         rip(p);
  752.  
  753.         /* if not in an matching entry skip continuation lines */
  754.         if (!inalias && isspace(*p))
  755.             continue;
  756.  
  757.         /* when processing an active alias check for a continuation */
  758.         if (inalias) {
  759.             if (!isspace(*p)) 
  760.                 break;    /* done */
  761.         } else {
  762.             s = p;
  763.             SKIPWORD(p);
  764.             *p++ = '\0';    /* end the alias name */
  765.             if (strcmp(s,user) != 0)
  766.                 continue;    /* no match go on */
  767.             inalias = 1;
  768.         }
  769.  
  770.         /* process the recipients on the alias line */
  771.         SKIPSPACE(p);
  772.         while(*p != '\0' && *p != '#') {
  773.             s = p;
  774.             SKIPWORD(p);
  775.             if (*p != '\0')
  776.                 *p++ = '\0';
  777.  
  778.             /* find hostname */
  779.             if ((h = index(s,'@')) != NULLCHAR)
  780.                 tp = addlist(head,s,DOMAIN);
  781.             else
  782.                 tp = addlist(head,s,LOCAL);
  783.             SKIPSPACE(p);
  784.         }
  785.     }
  786.     (void) fclose(fp);
  787.  
  788.     if (inalias)    /* found and processed and alias. */
  789.         return tp;
  790.  
  791.     /* no alias found treat as a local address */
  792.     return addlist(head, user, LOCAL);
  793. }
  794.